package deepbrain.simnetwork.demo;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import deepbrain.simnetwork.engine.ConcurrentEngine;
import deepbrain.simnetwork.engine.SimEngine;
import deepbrain.simnetwork.loader.NetworkLoader;
import deepbrain.simnetwork.loader.xml.XmlNetworkLoader;
import deepbrain.simnetwork.mechanism.Mechanism;
import deepbrain.simnetwork.mechanism.PLoSHopfieldMechanism;
import deepbrain.simnetwork.monitor.MonitorAdapter;
import deepbrain.simnetwork.monitor.NetworkStateLogMonitor;
import deepbrain.simnetwork.network.Network;
import deepbrain.simnetwork.network.NetworkState;
import deepbrain.simnetwork.network.NodeState;
import deepbrain.simnetwork.task.ConcurrentGroupTask;
import deepbrain.simnetwork.task.SimulationTask;
import deepbrain.simnetwork.task.Task;
import deepbrain.simnetwork.util.Counter;
import deepbrain.simnetwork.util.SimNetUtils;

/**
 * Statistics on the number of each states occured while simulating PLoS figure
 * #18 for every initial state.
 * 
 * 
 * @author Li Yang
 * @create 2009-2-30
 */
public class PLoSFig18Stat {

	private static final int NUM_OF_NODES = 8;
	/**
	 * For each init state, run 2000 time steps
	 */
	private static final int NUM_OF_STEPS = 2000;

	private static final String outputFilePath = "outputs/PLoSFig18Stat.out";

	public static void main(String[] args) throws Exception {

		// Load the network from XML and set the hopfield mechanism with 0.35
		// temperature
		NetworkLoader loader = new XmlNetworkLoader("networks/PLoS-fig18.xml");
		Network network = loader.loadNetwork();

		Mechanism mechanism = new PLoSHopfieldMechanism(0.35);
		network.setMechanism(mechanism);

		// Create a concurrent group task, which contains the sub tasks.
		final ConcurrentGroupTask groupTask = new ConcurrentGroupTask();

		// Create all of the initial states.
		List<NodeState[]> initStates = SimNetUtils
				.getAllCertainStates(NUM_OF_NODES);

		for (NodeState[] initState : initStates) {
			SimulationTask task = new SimulationTask(network, initState) {
				@Override
				public void runTask() {
					System.out.println(this + " start");
					runForSteps(NUM_OF_STEPS);
					System.out.println(this + " end");
				}
			};
			task.addTaskResult("init-state", new NetworkState(initState));
			task.addMonitor(new NetworkStateLogMonitor());
			groupTask.addTask(task);
		}

		// Count the num of each states after the "Group Task" finished.
		groupTask.addMonitor(new MonitorAdapter<ConcurrentGroupTask>() {
			@Override
			public void onTaskFinish(ConcurrentGroupTask task) {
				System.out.println("Simulation done.");
				System.out.println("Gathering statistics......");

				PrintWriter saver = SimNetUtils.getFileWriter(outputFilePath);
				saver
						.println("###################################### "
								+ NUM_OF_STEPS
								+ " Time Steps ######################################\n\n");
				for (Task eachTask : groupTask.getTasks()) {
					NetworkState initState = eachTask
							.getTaskResult("init-state");
					saver.println("For Initial State: "
							+ initState.toStringBrief());
					Counter<NetworkState> counter = new Counter<NetworkState>();
					ArrayList<NetworkState> states = eachTask
							.getTaskResult("state-log");
					for (NetworkState state : states)
						counter.increase(state);
					for (NetworkState state : counter.getSortedCountList()) {
						if (counter.getCount(state) < 10)
							continue;
						saver.println(state.toStringBrief() + "  occured\t"
								+ counter.getCount(state)
								+ "\ttimes.\tProportion:  "
								+ counter.getPorportion(state));
					}
					saver.println();
				}

				saver.flush();
				saver.close();
				System.out.println("done. Saved to " + outputFilePath);

				// Shutdown the door of the engine so that no more task can be
				// added to the engine.
				task.getThreadLocalEngine().shutdown();
			}
		});

		// After we arranged all of the things to be done.
		// We start the task by using a concurrent engine with 10 threads.
		SimEngine engine = new ConcurrentEngine(10);
		engine.runTask(groupTask);
	}
}
